package org.ns.basics.commons.util;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;

public class MapWrapper<K, V> {

    private final ConcurrentHashMap<K, V> map;

    public MapWrapper(ConcurrentHashMap<K, V> map) {
        this.map = map;
    }

    public MapWrapper() {
        map = new ConcurrentHashMap<>(128);
    }

    /**
     * 不存在则创建
     * @param key
     * @param instance 创建实例的方式
     * @return
     */
    public V get(K key, Supplier<V> instance) {
        V value = map.get(key);
        if (value == null) {
            synchronized (map) {
                value = map.get(key);
                if (value == null) {
                    value = instance.get();
                    if (value == null) {
                        throw new NullPointerException("");
                    }
                    map.put(key, value);
                }
            }
        }
        return value;
    }


    public V get(K key, Class<? extends V> instanceClass) {
        try {
            V value = map.get(key);
            if (value == null) {
                synchronized (map) {
                    value = map.get(key);
                    if (value == null) {
                        value = instanceClass.newInstance();
                        if (value == null) {
                            throw new NullPointerException("");
                        }
                        map.put(key, value);
                    }
                }
            }
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取不存在则创建
     * @param key
     * @param instance 创建实例的方式
     * @return
     */
    public V get(K key, Function<K, V> instance) {
        V value = map.get(key);
        if (value == null) {
            synchronized (map) {
                value = map.get(key);
                if (value == null) {
                    value = instance.apply(key);
                    map.put(key, value);
                }
            }
        }
        return value;
    }

    public ConcurrentHashMap<K, V> getMap() {
        return map;
    }

    public Set<Map.Entry<K,V>> entrySet() {
        return this.map.entrySet();
    }

    public Set<K> keySet() {
        return this.map.keySet();
    }

    public Collection<V> values() {
        return this.map.values();
    }

    public V put(K key, V value) {
        return this.map.put(key, value);
    }

    public void putAll(Map<K,V> m) {
        this.map.putAll(m);
    }

    public int size() {
        return this.map.size();
    }

}
